/*
 * protocol.h
 *
 *  Created on: Mar 24, 2012
 *      Author: Victor Nidens
 */

#ifndef PROTOCOL_H_
#define PROTOCOL_H_

#include <iostream>
#include <string.h>
#include <sys/time.h>

#define uint8   unsigned char
#define int8    char
#define uint16  unsigned short
#define int16   short
#if ULONG_MAX >> 32 == 0
#define uint32  unsigned long
#define int32   long
#else
#define uint32  unsigned int
#define int32   int
#endif
#define uint64  unsigned long long
#define int64   long long

using namespace std;

//commands constants
#define COMMAND_PING						0xFF
#define COMMAND_READ_SENSOR_REQUEST			0x10	//should be used for fetching info from analog sensors
#define COMMAND_READ_SENSOR_RESPONSE		0x11
#define COMMAND_WRITE_SENSOR_REQUEST		0x20	//should be used for I2C sensors config
#define COMMAND_WRITE_SENSOR_RESPONSE		0x21
#define COMMAND_READ_MOTOR_REQUEST			0x30
#define COMMAND_READ_MOTOR_RESPONSE			0x31
#define COMMAND_WRITE_MOTOR_REQUEST			0x40
#define COMMAND_WRITE_MOTOR_RESPONSE		0x41
#define COMMAND_SYSTEM_REQUEST				0x50
#define COMMAND_SYSTEM_RESPONSE				0x51
#define COMMAND_DEVICE_ANNOUNCE				0x60	//should be used for announcing connected NXT devices to the server
#define COMMAND_DEVICE_ANNOUNCE_RESPONSE	0x61
#define COMMAND_INIT_SENSOR_REQUEST			0x70	//should be used for initializing sensors on the NXT device
#define COMMAND_INIT_SENSOR_RESPONSE		0x71

//protocols constants
#define PROTOCOL_SAME	0
#define PROTOCOL_TCP	1
#define PROTOCOL_UDP	2

//data formats
#define FORMAT_RAW		0x10

#pragma pack(1)
typedef struct {
	char deviceName[16];
	uint8 port;
	uint8 sensor;
	uint8 dataFormat;
	uint8 dataSize;
	uint8 data[28];
} Device;

#pragma pack(1)
typedef struct {
	uint8	command;
	uint16	repeatsNumber;
	uint16	repeatDelay;		//ms
	uint8	responseProtocol;
	char 	dst[16];
} Command;

#pragma pack(1)
typedef struct {
	uint8	sourceIp[4];
	char	sourceName[16];
	uint8	sourceProtocol;
	int64	timestampSec;
	int64	timestampUsec;
} Source;

#pragma pack(1)
typedef struct {
	Command 		command;
	Source 			source;
	Device			deviceData;
	struct timeval	receivedTimestamp;
} ExchangePacket;

//Only Command, Source and Device subfields
//of the ExchangePacket struct should be
//sent over the network, so just pre-define
//their size for convenience
#define NETWORK_PACKET_SIZE (sizeof(Device) + sizeof(Command) + sizeof(Source))

/**
 * Fill Source struct object with info about the packet source
 *
 * @param dst			Source object to fill in (return parameter)
 * @param sourceIP		IP address of the packet source (array of 4 uint16 elements)
 * @param sourceName	Human readable of the packet source
 * @param protocol		Protocol which will be used to send the packet
 *
 * @return
 */
void fillSourceInfo(Source *dst, uint8* sourceIP, string sourceName, uint8 protocol);

/**
 * Copies info from one Source object to another with updating timestamps
 *
 * @param dst			Source object where to copy info (return parameter)
 * @param src			Source object with info to be copied
 *
 * @return
 */
void fillSourceInfo(Source *dst, Source *src);

/**
 * Build Command struct object
 *
 * @param command			Command object to store result (return parameter)
 * @param commandId			ID of the command
 * @param dstName			Name of the client which must accept the command
 * @param repeats			How many times client should execute the command
 * @param delay				Delay between executions of the command
 * @param responseProtocol	Protocol which client should use to send the response
 *
 * @return
 *
 */
void constructCommand(Command *command, uint8 commandId, char *dstName, uint16 repeats, uint16 delay, uint8 responseProtocol);

/**
 * Returns the human readable command name.
 *
 * @param commandId		ID of the command
 *
 * @return				String with command name if command was found. Empty string in another case.
 *
 */
char* commandName(uint8 commandId);

#endif /* PROTOCOL_H_ */
